import { Worker } from "worker_threads";

class WorkerPool {
  constructor(workerPath, poolSize = 4, defaultTimeout = 8000) {
    this.workerPath = workerPath;
    this.poolSize = poolSize;
    this.defaultTimeout = defaultTimeout; // 默认任务超时时间（毫秒）
    this.workers = [];
    this.idleWorkers = [];
    this.queue = [];

    for (let i = 0; i < poolSize; i++) {
      const worker = this.createWorker();
      this.workers.push(worker);
      this.idleWorkers.push(worker);
    }
  }
  /**
   * 创建一个新的工作线程
   * @returns {Object} - 新创建的工作线程对象
   */
  createWorker() {
    const worker = new Worker(this.workerPath, { type: "module" });
    worker.isBusy = false;
    worker.currentTask = null;

    /**
     * 监听 worker 的 message 事件
     * 当 worker 发送消息时，此事件会被触发
     * @param {Object} result - worker 发送的消息
     */
    worker.on("message", (result) => {
      // console.warn("WorkerPool 接收到消息", Date.now());
      if (worker.currentTask) {
        const { resolve, timeoutId } = worker.currentTask;
        clearTimeout(timeoutId); // 清除超时计时器
        resolve(result);
        worker.currentTask = null;
      }
      worker.isBusy = false;
      this.idleWorkers.push(worker);
      this.checkQueue();
    });

    /**
     * 监听 worker 的 error 事件
     * 当 worker 发生错误时，此事件会被触发
     * @param {Object} err - 发生的错误
     */
    worker.on("error", (err) => {
      console.error("❌ WorkerPool error:", err);
      if (worker.currentTask) {
        const { reject, timeoutId } = worker.currentTask;
        clearTimeout(timeoutId);
        reject(err);
        worker.currentTask = null;
      }
      this.handleWorkerCrash(worker);
    });

    /**
     * 监听 worker 的 exit 事件
     * 当 worker 退出时，此事件会被触发
     * @param {number} code - worker 退出时的状态码
     */
    worker.on("exit", (code) => {
      if (code !== 0) {
        console.error(`❌ Worker exited with code ${code}`);
      }
      this.handleWorkerCrash(worker);
    });

    return worker;
  }

  /**
   * 处理工作线程崩溃或意外退出的情况
   * @param {Object} worker - 发生故障的工作线程对象
   * @returns {void} - 无返回值
   */
  handleWorkerCrash(worker) {
    // 如果 Worker 异常退出或出错，处理当前任务
    if (worker.currentTask) {
      const { reject, timeoutId } = worker.currentTask;
      clearTimeout(timeoutId);
      reject(new Error("Worker crashed or exited unexpectedly"));
      worker.currentTask = null;
    }
    // 移除故障的 Worker，并创建新的 Worker
    this.removeWorker(worker);
    const newWorker = this.createWorker();
    this.workers.push(newWorker);
    this.idleWorkers.push(newWorker);
    // 检查任务队列
    this.checkQueue();
  }

  removeWorker(worker) {
    this.workers = this.workers.filter((w) => w !== worker);
    this.idleWorkers = this.idleWorkers.filter((w) => w !== worker);
  }

  runTask(workerData, timeout = this.defaultTimeout) {
    return new Promise((resolve, reject) => {
      const task = { workerData, resolve, reject, timeout };
      const worker = this.idleWorkers.shift();

      if (worker) {
        this.assignTask(worker, task);
      } else {
        this.queue.push(task);
      }
    });
  }

  assignTask(worker, task) {
    worker.isBusy = true;
    worker.currentTask = task;

    // 设置任务超时计时器
    const timeoutId = setTimeout(() => {
      // 任务超时，拒绝 Promise
      if (worker.currentTask === task) {
        task.reject(new Error("Task timed out"));
        worker.currentTask = null;
        worker.isBusy = false;

        // 处理卡住的 Worker
        this.terminateWorker(worker);
      }
    }, task.timeout);

    task.timeoutId = timeoutId; // 将计时器 ID 保存到任务中

    worker.postMessage(task.workerData); // 这行代码将任务数据发送给工作线程，以便它可以开始执行任务。
  }

  terminateWorker(worker) {
    // 终止卡住的 Worker，并创建新的 Worker
    worker.terminate();
    this.removeWorker(worker);
    const newWorker = this.createWorker();
    this.workers.push(newWorker);
    this.idleWorkers.push(newWorker);

    // 检查是否有等待的任务
    this.checkQueue();
  }

  checkQueue() {
    while (this.queue.length > 0 && this.idleWorkers.length > 0) {
      const task = this.queue.shift();
      const worker = this.idleWorkers.shift();
      this.assignTask(worker, task);
    }
  }
}

export default WorkerPool;
